//
// Created by LONG on 2020/10/18.
//


#include <stdio.h>
#include <stdarg.h>
#include <iostream>
#include "../lib/doctest.h"
#include "../../include/utils/fsm.h"

using namespace std;

uint32_t testTime = 0;

typedef enum {
    FSM_TEST_STATE_IDLE,
    FSM_TEST_STATE_WAIT_ACK,
    FSM_TEST_STATE_WAIT_CLOSE,
} E_FsmTestState;

typedef enum {
    FSM_TEST_EVENT_CONNECT,
    FSM_TEST_EVENT_RCV_ACK,
    FSM_TEST_EVENT_CLOSE,
} E_FsmTestEvent;

typedef enum {
    FSM_TEST_RESULT_OK,
    FSM_TEST_RESULT_ERR,
} E_FsmTestResult;

void ut_fsm_log_print(uint32_t type, const char *fmt, ...)
{
    va_list vl;

    va_start(vl, fmt);
    vprintf(fmt, vl);
    va_end(vl);
}

void fsm_test_default_handler1(uint32_t state, S_FsmEventContext *evt_ctxt, S_FsmHandleResult *result)
{
    result->procRslt = FSM_TEST_RESULT_OK;
}

void fsm_test_idle_state_handler1(uint32_t state, S_FsmEventContext *evt_ctxt, S_FsmHandleResult *result)
{
    result->procRslt = FSM_TEST_RESULT_OK;
}

void fsm_test_wait_ack_state_handler1(uint32_t state, S_FsmEventContext *evt_ctxt, S_FsmHandleResult *result)
{
    if (testTime % 2 == 0)
    {
        result->procRslt = FSM_TEST_RESULT_OK;
    }
    else
    {
        result->procRslt = FSM_TEST_RESULT_ERR;
    }
    testTime++;
}

void fsm_test_wait_close_state_handler1(uint32_t state, S_FsmEventContext *evt_ctxt, S_FsmHandleResult *result)
{
    result->procRslt = FSM_TEST_RESULT_OK;
}

FSM_DEF_BEG(TEST_FSM1, FSM_TEST_STATE_IDLE)
    FSM_STATE_DEF_BEG(FSM_TEST_STATE_IDLE)
    FSM_EVENT_HANDLE_DEF(FSM_TEST_EVENT_CONNECT, fsm_test_idle_state_handler1)
    FSM_STATE_TRANS_DEF(FSM_TEST_RESULT_OK, FSM_TEST_STATE_WAIT_ACK)
    FSM_STATE_DEF_END(FSM_TEST_STATE_IDLE)

    FSM_STATE_DEF_BEG(FSM_TEST_STATE_WAIT_ACK)
    FSM_DEFAULT_EVENT_HANDLE_DEF(fsm_test_default_handler1)
    FSM_STATE_TRANS_DEF(FSM_TEST_RESULT_OK, FSM_TEST_STATE_IDLE)
    FSM_EVENT_HANDLE_DEF(FSM_TEST_EVENT_RCV_ACK, fsm_test_wait_ack_state_handler1)
    FSM_STATE_TRANS_DEF(FSM_TEST_RESULT_OK, FSM_TEST_STATE_WAIT_CLOSE)
    FSM_STATE_TRANS_DEF(FSM_TEST_RESULT_ERR, FSM_TEST_STATE_IDLE)
    FSM_STATE_DEF_END(FSM_TEST_STATE_WAIT_ACK)

    FSM_STATE_DEF_BEG(FSM_TEST_STATE_WAIT_CLOSE)
    FSM_EVENT_HANDLE_DEF(FSM_TEST_EVENT_CLOSE, fsm_test_wait_close_state_handler1)
    FSM_STATE_TRANS_DEF(FSM_TEST_RESULT_OK, FSM_TEST_STATE_IDLE)
    FSM_STATE_DEF_END(FSM_TEST_STATE_WAIT_CLOSE)
FSM_DEF_END(TEST_FSM1)

TEST_SUITE ("FSM_TS")
{
    TEST_CASE ("FSM_TC1")
    {
        uint64_t timeStamp;
        uint64_t lastTick;

        int32_t rc;
        S_Fsm *fsm;
        S_FsmInst *sm_inst;
        S_FsmEventContext evt_ctxt;

        fsm = FSM_INIT(TEST_FSM1);
        REQUIRE(fsm);
        FSM_SetLogCallback(fsm, ut_fsm_log_print);
        sm_inst = FSM_INST_Init(fsm, "sm_inst");
        REQUIRE(sm_inst);
        REQUIRE(FSM_TEST_STATE_IDLE == FSM_INST_GetState(sm_inst));

        evt_ctxt.event = FSM_TEST_EVENT_CONNECT;
        rc = FSM_INST_HandleEvent(sm_inst, &evt_ctxt);
        REQUIRE(FSM_RC_OK == rc);
        REQUIRE(FSM_TEST_STATE_WAIT_ACK == FSM_INST_GetState(sm_inst));

        evt_ctxt.event = FSM_TEST_EVENT_CONNECT;
        rc = FSM_INST_HandleEvent(sm_inst, &evt_ctxt);
        REQUIRE(FSM_RC_OK == rc);
        REQUIRE(FSM_TEST_STATE_IDLE == FSM_INST_GetState(sm_inst));

        evt_ctxt.event = FSM_TEST_EVENT_CONNECT;
        rc = FSM_INST_HandleEvent(sm_inst, &evt_ctxt);
        REQUIRE(FSM_RC_OK == rc);
        REQUIRE(FSM_TEST_STATE_WAIT_ACK == FSM_INST_GetState(sm_inst));

        evt_ctxt.event = FSM_TEST_EVENT_RCV_ACK;
        rc = FSM_INST_HandleEvent(sm_inst, &evt_ctxt);
        REQUIRE(FSM_RC_OK == rc);
        REQUIRE(FSM_TEST_STATE_WAIT_CLOSE == FSM_INST_GetState(sm_inst));

        evt_ctxt.event = FSM_TEST_EVENT_CLOSE;
        rc = FSM_INST_HandleEvent(sm_inst, &evt_ctxt);
        REQUIRE_EQ(FSM_RC_OK, rc);
        REQUIRE_EQ(FSM_TEST_STATE_IDLE, FSM_INST_GetState(sm_inst));

        evt_ctxt.event = FSM_TEST_EVENT_CONNECT;
        rc = FSM_INST_HandleEvent(sm_inst, &evt_ctxt);
        REQUIRE_EQ(FSM_RC_OK, rc);
        REQUIRE_EQ(FSM_TEST_STATE_WAIT_ACK, FSM_INST_GetState(sm_inst));

        evt_ctxt.event = FSM_TEST_EVENT_RCV_ACK;
        rc = FSM_INST_HandleEvent(sm_inst, &evt_ctxt);
        REQUIRE_EQ(FSM_RC_OK, rc);
        REQUIRE_EQ(FSM_TEST_STATE_IDLE, FSM_INST_GetState(sm_inst));

        FSM_INST_Reset(sm_inst);
        FSM_INST_Final(sm_inst);

        FSM_Final(fsm);
    }
}



void fsm_test_idle_state_default_handler2(uint32_t state, S_FsmEventContext *evt_ctxt, S_FsmHandleResult *result)
{
    result->procRslt = FSM_TEST_RESULT_OK;
    result->newEventInd = 1;
    result->newEvent = FSM_TEST_EVENT_RCV_ACK;
}

void fsm_test_idle_state_handler2(uint32_t state, S_FsmEventContext *evt_ctxt, S_FsmHandleResult *result)
{
    result->procRslt = FSM_TEST_RESULT_OK;
    result->newEventInd = 1;
    result->newEvent = FSM_TEST_EVENT_RCV_ACK;
}

void fsm_test_wait_ack_state_handler2(uint32_t state, S_FsmEventContext *evt_ctxt, S_FsmHandleResult *result)
{
    result->procRslt = FSM_TEST_RESULT_OK;
    result->newEventInd = 1;
    result->newEvent = FSM_TEST_EVENT_CLOSE;
}

void fsm_test_wait_close_state_handler2(uint32_t state, S_FsmEventContext *evt_ctxt, S_FsmHandleResult *result)
{
    result->procRslt = FSM_TEST_RESULT_OK;
}

FSM_DEF_BEG(TEST_FSM2, FSM_TEST_STATE_IDLE)
    FSM_STATE_DEF_BEG(FSM_TEST_STATE_IDLE)
    FSM_DEFAULT_EVENT_HANDLE_DEF(fsm_test_idle_state_default_handler2)
    FSM_STATE_TRANS_DEF(FSM_TEST_RESULT_OK, FSM_TEST_STATE_WAIT_ACK)
    FSM_EVENT_HANDLE_DEF(FSM_TEST_EVENT_CONNECT, fsm_test_idle_state_handler2)
    FSM_STATE_TRANS_DEF(FSM_TEST_RESULT_OK, FSM_TEST_STATE_WAIT_ACK)
    FSM_STATE_DEF_END(FSM_TEST_STATE_IDLE)

    FSM_STATE_DEF_BEG(FSM_TEST_STATE_WAIT_ACK)
    FSM_EVENT_HANDLE_DEF(FSM_TEST_EVENT_RCV_ACK, fsm_test_wait_ack_state_handler2)
    FSM_STATE_TRANS_DEF(FSM_TEST_RESULT_OK, FSM_TEST_STATE_WAIT_CLOSE)
    FSM_STATE_DEF_END(FSM_TEST_STATE_WAIT_ACK)

    FSM_STATE_DEF_BEG(FSM_TEST_STATE_WAIT_CLOSE)
    FSM_EVENT_HANDLE_DEF(FSM_TEST_EVENT_CLOSE, fsm_test_wait_close_state_handler2)
    FSM_STATE_TRANS_DEF(FSM_TEST_RESULT_OK, FSM_TEST_STATE_IDLE)
    FSM_STATE_DEF_END(FSM_TEST_STATE_WAIT_CLOSE)
FSM_DEF_END(TEST_FSM2)

TEST_SUITE ("FSM_TS")
{
    TEST_CASE ("FSM_TC2")
    {
            SUBCASE("HASH_TABLE_SC_BASE")
        {
            int32_t rc;
            S_Fsm *fsm;
            S_FsmInst *sm_inst;
            S_FsmEventContext evt_ctxt;

            fsm = FSM_INIT(TEST_FSM2);
            REQUIRE(fsm);
            FSM_SetLogCallback(fsm, ut_fsm_log_print);
            sm_inst = FSM_INST_Init(fsm, "sm_inst");
            REQUIRE(sm_inst);
            REQUIRE_EQ(FSM_TEST_STATE_IDLE, FSM_INST_GetState(sm_inst));

            evt_ctxt.event = FSM_TEST_EVENT_CONNECT;
            rc = FSM_INST_HandleEvent(sm_inst, &evt_ctxt);
            REQUIRE_EQ(FSM_RC_OK, rc);
            REQUIRE_EQ(FSM_TEST_STATE_IDLE, FSM_INST_GetState(sm_inst));

            FSM_INST_Reset(sm_inst);
            FSM_INST_Final(sm_inst);

            FSM_Final(fsm);
        }

            SUBCASE("HASH_TABLE_SC_BASE2")
        {
            int32_t rc;
            S_Fsm *fsm;
            S_FsmInst *sm_inst;
            S_FsmEventContext evt_ctxt;

            fsm = FSM_INIT(TEST_FSM2);
            REQUIRE(fsm);
            FSM_SetLogCallback(fsm, ut_fsm_log_print);
            sm_inst = FSM_INST_Init(fsm, "sm_inst");
            REQUIRE(sm_inst);
            REQUIRE_EQ(FSM_TEST_STATE_IDLE, FSM_INST_GetState(sm_inst));

            evt_ctxt.event = FSM_TEST_EVENT_RCV_ACK;
            rc = FSM_INST_HandleEvent(sm_inst, &evt_ctxt);
            REQUIRE_EQ(FSM_RC_OK, rc);
            REQUIRE_EQ(FSM_TEST_STATE_IDLE, FSM_INST_GetState(sm_inst));

            FSM_INST_Reset(sm_inst);
            FSM_INST_Final(sm_inst);

            FSM_Final(fsm);
        }
    }
}
